為什麼從建立一個測試網站開始,在網站安全教學的過程中,如果直接從工具上手,多半會變成腳本小子,你會知道工具怎麼用,但不知道底層原理是什麼,因此這個系列會透過撰寫「有問題的網站」來講解漏洞的原理與成因,期待讓網站工程師更了解事情經過。
本次我們將透過 Node.js 來建立一個不安全的網站與功能,以便學習和測試網站安全。這個過程將幫助我們理解網站架構,並為後續的安全測試奠定基礎。
在開始之前,請確保系統已經安裝以下工具:
https://github.com/fei3363/ithelp_web_security_2024/commit/c953c613f907b932eda267169605fb7f705b322b
讓我們逐步建立必要的檔案和設定:
這個檔案定義了我們的應用服務和資料庫服務:
version: '3'
services:
app:
build:
context: ./web
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- MONGODB_URI=mongodb://mongo:27017/myapp
- NODE_ENV=development
depends_on:
- mongo
volumes:
- ./web:/usr/src/app
- /usr/src/app/node_modules
mongo:
image: mongo:latest
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
volumes:
mongodb_data:
這個 Dockerfile 用於建構我們的 Node.js 應用程式容器:
FROM node:14
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "npm", "run", "dev" ]
定義了我們的 Node.js 應用程式相依套件和腳本:
{
"name": "nodejs-docker-app",
"version": "1.0.0",
"description": "A simple Node.js app with Docker",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
這是我們的前端頁面:
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>測試網頁</title>
<style>
body { font-family: "微軟正黑體", Arial, sans-serif; text-align: center; padding-top: 50px; }
#message { margin-top: 20px; font-weight: bold; }
</style>
</head>
<body>
<h1>歡迎來到測試網頁</h1>
<p>這是一個由 Express.js 建立的簡單測試頁面</p>
<button onclick="fetchMessage()">從 API 取得資訊</button>
<div id="message"></div>
<script>
function fetchMessage() {
fetch('/api/hello')
.then(response => response.json())
.then(data => {
document.getElementById('message').innerText = data.message;
})
.catch(error => console.error('錯誤:', error));
}
</script>
</body>
</html>
這是我們的後端伺服器程式碼:
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from the server!' });
});
app.listen(port, () => {
console.log(`伺服器執行在 http://localhost:${port}`);
});
透過這個設定,我們可以了解到基本的網站架構:
Node.js 允許我們使用 JavaScript 來編寫伺服器端程式碼。在我們的例子中:
sendFile
方法直接發送到使用者端。/api/hello
)透過 app.get()
方法定義,並回傳 JSON 資料。為了方便讀者學習,我在自己的網站上架設了相同的實驗環境,以利大家學習網站安全。
大家可以瀏覽 nodelab.feifei.tw 來觀察這個實驗環境。進入網站後,我們可以觀察幾個重要的事項:
當您瀏覽 nodelab.feifei.tw 時,瀏覽器會顯示這是一個不安全的網站。
開發者工具是學習和分析網站安全的重要工具。以下是如何開啟和使用開發者工具:
開啟方式:
使用開發者工具觀察:
安全相關觀察:
透過使用開發者工具,我們可以深入了解網站的運作方式,這對於識別潛在的安全問題非常有幫助。在接下來的課程中,我們將更詳細地探討如何利用這些工具來發現和分析各種安全漏洞。
練習:
在這個練習中,我們將深入了解當我們存取一個網站時,瀏覽器與伺服器之間實際發生的通訊過程。我們會特別關注請求封包(Request)和回應封包(Response)的內容。
步驟:
在網路請求列表中,找到並點選 nodelab.feifei.tw 的請求:
接下來,我們將分別查看請求封包和回應封包的內容。
在右側面板中,切換到「標頭」(Headers)分頁,然後勾選顯示「原始」(Raw)選項來查看原始的請求標頭:
請求封包內容解釋:
GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-TW;q=0.8,zh;q=0.7,en-GB;q=0.6
Cache-Control: no-cache
Connection: keep-alive
Host: nodelab.feifei.tw
Pragma: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0
GET /
: 這是 HTTP 方法和請求的路徑。GET 表示我們想要獲取資源,/
表示我們請求的是網站的根目錄。Accept
: 指定使用者端能夠接受的內容類型。Accept-Encoding
: 指定使用者端能夠接受的內容編碼方式。Accept-Language
: 指定使用者端偏好的語言。Cache-Control
和 Pragma
: 用於控制快取行為。Host
: 指定請求的目標主機。Upgrade-Insecure-Requests
: 表示使用者端支持升級到 HTTPS 連接。User-Agent
: 提供有關使用者端瀏覽器和作業系統的資訊。同樣在「標頭」分頁中,我們可以查看伺服器的回應標頭:
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 14 Sep 2024 15:21:34 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=0
Last-Modified: Sat, 14 Sep 2024 14:42:57 GMT
ETag: W/"3be-191f0fcaf94"
Content-Encoding: gzip
回應封包內容解釋:
HTTP/1.1 200 OK
: 表示請求成功。Server
: 指出伺服器使用軟體與作業系統。
Date
: 回應的日期和時間。Content-Type
: 指定回應內容的類型。Transfer-Encoding
: 指定回應內容的傳輸編碼方式。Connection
: 指定連接的狀態。X-Powered-By
: 額外資訊,使用了 Express 框架。
Cache-Control
: 指定快取控制策略。Last-Modified
: 資源最後修改的時間。ETag
: 資源的版本標識符。Content-Encoding
: 指定回應內容的編碼方式。User-Agent
可能洩漏使用者端軟體版本。Strict-Transport-Security
、Content-Security-Policy
等。Server
和 X-Powered-By
標頭可能洩漏伺服器和框架版本,這可能被攻擊者利用。通過分析這些封包,我們可以更好地理解網站的運作方式,並識別潛在的安全問題。
在這個練習中,我們將觀察並分析一個簡單的 API 呼叫。這將幫助我們了解前端如何與後端通訊,以及如何識別和檢查 API 請求。
步驟:
application/json; charset=utf-8
/api/hello
/api/hello
的完整請求和回應內容。在這篇文章中,我們深入探討了如何建立一個基本的網站環境,並學習了分析網站結構和通訊的基礎知識。以下是本篇的主要重點:
這些知識為我們後續深入研究網站安全提供了重要的基礎。在接下來的文章中,我們將基於這些基礎知識,進一步探討更多具體的網站安全問題和解決方案。